﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace PascalTriangle
{
    public class Solver
    {
        private TriangleContainer container;
        private bool allSolved;

        private int id;
        public int ID
        {
            get { return id; }
            set { id = value; }
        }

        private int points;
        public int Points
        {
            get { return points; }
            set { points = value; }
        }


        public Solver(TriangleContainer container, int ID)
        {
            this.container = container;
            this.allSolved = false;
            this.id = ID;
            this.points = 0;
        }

        public void Run()
        {
            while (!allSolved)
            {
                if (container.IsSolved())
                {
                    allSolved = true;
                }
                else
                {
                    //Przeszukujemy trókąt
                    int level = container.Level;
                    long val;

                    for (int i = 0; i < level; i++)
                    {
                        for (int j = 0; j <= i; j++)
                        {
                            //Szukamy nie rozwiązanego jeszcze elementu
                            //val = container.GetValue(i, j);

                            //Znaleziono element nie rozwiązany jeszcze, spróbujmy go oznaczyć do jako do rozwiązania
                            //if (val == -1)
                            {
                                if (container.CheckElement(i, j, id))
                                {
                                    //OK udało nam sie go oznaczyć, spróbujmy go rozwiazać
                                    if (i == 0 || j == 0 || j == i)
                                    {
                                        //Elementy brzegowe na 1
                                        container.SetValue(i, j, 1, id);
                                        points++;
                                        Thread.Sleep(1);
                                    }
                                    else
                                    {
                                        //Liczmy sumę
                                        ulong sum, val1, val2;
                                        int id1, id2;
                                        int cnt = 0;

                                        val1 = container.GetValue(i - 1, j - 1);
                                        val2 = container.GetValue(i - 1, j);
                                        id1 = container.GetThreadID(i - 1, j - 1);
                                        id2 = container.GetThreadID(i - 1, j);
                                        
                                        
                                        if (val1 == 0 || val2 == 0)
                                        {
                                            //Sprawdźmy czy którs wątek to liczy
                                            if (id1 >= 0 || id2 >= 0)
                                            {
                                                //Wątki jeszcze liczą wartości, poczekajmy chwilę
                                                do
                                                {
                                                    Thread.Sleep(50);
                                                    val1 = container.GetValue(i - 1, j - 1);
                                                    val2 = container.GetValue(i - 1, j);
                                                    id1 = container.GetThreadID(i - 1, j - 1);
                                                    id2 = container.GetThreadID(i - 1, j);

                                                    if (id1 < 0 || id2 < 0)
                                                        break;

                                                    cnt++;
                                                } while ((val1 == 0 || val2 == 0) && cnt <= 10);
                                            }
                                        }

                                        //Poprzednie elementy nie zostały jeszcze obliczone
                                        if (id1 < 0 || id2 < 0)
                                        {
                                            //Skoro nie jest obliczona ktoraś z poprzednich wartości to cofnijmy watek do tego miejsca
                                            // i każmy mu obliczyć te wartości.

                                            if (id2 < 0)
                                            {
                                                container.UncheckElement(i, j);
                                                i = i - 1;
                                                j = j - 1; //Hack                                               
                                            }

                                            if (id1 < 0)
                                            {
                                                container.UncheckElement(i, j);
                                                i = i - 1;
                                                j = j - 2;  //Hack na continue                                            
                                            }                                           

                                            continue;
                                        }

                                        //Coś jest nie tak, wątki nie zdażyly sie wyrobić w czasie
                                        //Trudno lecimy dalej
                                        if (val1 == 0 || val2 == 0 || cnt == 10)
                                        {
                                            continue;
                                        }

                                        sum = val1 + val2;
                                        container.SetValue(i, j, sum, id);
                                        points++;
                                        Thread.Sleep(1);
                                    }                         

                                }                                
                            }
                        }
                    }

                    //int i,j;
                    //Szukamy pierwszego wolnego elementu i go oznaczamy
                    //container.FindFirstAndCheck(out i, out j);

                }               

            }
        }
    }
}
